<?php

namespace ulue\parts\session;

use Ulue;
use ulue\libs\traits\TraitGetOption;
use ulue\parts\session\handler\InterfaceSessionHandler;
use ulue\parts\session\handler\NatureSessionHandler;
use ulue\parts\session\operator\InterfaceSessionOperator;
use ulue\parts\session\operator\SessionOperator;


abstract class AbstractSession implements \ArrayAccess, \IteratorAggregate
{
    /**
     * @var object handler
     */
    protected $handler = null;
    protected $operator = null;
    protected $launch  = null;
    protected $cookie  = [];

    /**
     * 获取选项
     */
    use TraitGetOption;


    /**
     * @param InterfaceSessionHandler $handler 定义session处理者
     * @param InterfaceSessionLauncher $launch session 启动管理
     * @param InterfaceSessionOperator $operator session 数据操作
     * @param array $options 选项
     */
    public function __construct(
        InterfaceSessionHandler $handler=null, InterfaceSessionLauncher $launch=null,
        InterfaceSessionOperator $operator=null,   array $options=[]
    ) {
        $this->handler  = $handler  instanceof InterfaceSessionHandler  ? $handler  : new NatureSessionHandler();
        $this->operator = $operator instanceof InterfaceSessionOperator ? $operator : new SessionOperator();
        $this->launch   = $launch   instanceof InterfaceSessionLauncher   ? $launch   : new SessionLauncher();
        $this->options  = $options;

        \Debug::trace('为启动session做准备！',[
            '@property $options' => $this->options
        ]);

        $this->init();
    }

    public function init()
    {
        if ($name = $this->getOption('name'))
        {
            $this->launch->setName(md5($name));
        }

        // Set id
        if ($this->getOption('id'))
        {
            $this->launch->setId($this->getOption('id'));
        }

        // Sync the session maxlifetime
        ini_set('session.gc_maxlifetime', $this->getOption('expire_time') * 60);

    }

    protected function getCookieParams()
    {
        return $this->launch->getCookieParams();
    }

    /**
     * Set session cookie parameters, this method should call before session started.
     * @return  void
     */
    protected function setCookieParams()
    {
        $cookie = $this->getCookieParams();

        // 强制 ssl
        if ($this->getOption('force_ssl'))
        {
            $cookie['secure'] = true;
        }

        // 限制域名
        if ($this->getOption('cookie_domain'))
        {
            $cookie['domain'] = $this->getOption('cookie_domain');
        }

        // 设置路径
        if ($this->getOption('cookie_path'))
        {
            $cookie['path'] = $this->getOption('cookie_path');
        }

        $this->launch->setCookieParams($cookie['lifetime'], $cookie['path'], $cookie['domain'], $cookie['secure'], true);
    }

    public function getOperator()
    {
        return $this->operator;
    }

    public function setOperator(InterfaceSessionOperator $operator)
    {
        $this->operator = $operator;

        return $this;
    }

    public function getHandler()
    {
        return $this->handler;
    }

    /**
     * @param InterfaceSessionHandler $handler
     * @return $this
     */
    public function setHandler(InterfaceSessionHandler $handler)
    {
        $this->handler = $handler;

        return $this;
    }

    public function clean()
    {

    }


    protected function close()
    {
        $this->launch->save();

        return true;
    }

    /**
     * Get session name
     * @return  string  The session name
     *
     */
    public function getName()
    {
        return $this->launch->getName();
    }

    /**
     * Get session id
     * @return  string  The session name
     * @return  string  The session name
     */
    public function getId()
    {

        return $this->launch->getId();
    }

    /**
     * Create a token-string
     * @param   integer  $length  Length of string
     * @return  string  Generated token
     */
    protected function createToken($length = 32)
    {
        static $chars = '0123456789abcdef';
        $max = strlen($chars) - 1;
        $token = '';
        $name = $this->getName();

        for ($i = 0; $i < $length; ++$i)
        {
            $token .= $chars[(rand(0, $max))];
        }

        return md5($token . $name);
    }


    /**
     * Get cookie source, default is $_COOKIE.
     * @return  array  Cookie source
     */
    public function getCookie()
    {
        if ($this->cookie === null)
        {
            $this->cookie = &$_COOKIE;
        }

        return $this->cookie;
    }

    /**
     * Set cookie source. default will be $_COOKIE.
     * Set this property to your array to help you test.
     * @param   array  $cookie  Cookie source.
     * @return  Session  Return self to support chaining.
     */
    public function setCookie($cookie)
    {
        $this->cookie = $cookie;

        return $this;
    }


}